package edu.rit.drh4818.fire;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;
import javax.vecmath.Color3f;

import edu.rit.drh4818.fire.colormap.*;
import edu.rit.drh4818.fire.data.*;
import edu.rit.drh4818.fire.emitter.*;
import edu.rit.drh4818.volume.*;


/**
 * 
 * Frame to display volume renderer, using the fire data sets.
 * 
 * @author Darren Headrick
 *
 */
@SuppressWarnings("serial")
public class FireRenderer extends JPanel implements ActionListener, KeyListener
{
	/**
	 * The list of available configurations.
	 */
	public static List<Colormap> maps = new ArrayList<Colormap>();
	public static List<Volume> volumes = new ArrayList<Volume>();
	public static List<Emitter> emits = new ArrayList<Emitter>();
	
	/**
	 * Possible scale values.
	 */
	private static Float[] scales = { .5F, .7F, .9F, 1F, 1.1F, 1.2F, 1.5F };
	
	/**
	 * Possible delay values.
	 */
	private static Integer[] delays = { 1,2,3,4,5,10,30};
	
	/**
	 * UI selectors.
	 */
	private JComboBox cmaps, data, emit, scale, delay;
	private JButton openChooser;
	
	/**
	 * Canvas which is rendering the volume.
	 */
	private VolumeCanvas volRend;
	
	/**
	 * The last known volume that was rendered. If this changes, need to create a new
	 *  volume canvas to render it.
	 */
	private Volume last;
	
	/**
	 * Background color.
	 */
	private Color3f background = new Color3f( new Color( .5F, .5F, .5F ) );
	
	
	/**
	 * Initialize frame. Settings default to first in each list.
	 */
	public FireRenderer() 
	{
		super( new BorderLayout() );
		
		// set up the confiugration options panel
		JPanel config = new JPanel();
		config.setLayout( new BoxLayout( config, BoxLayout.X_AXIS) );
		
		cmaps = new JComboBox( maps.toArray() );
		cmaps.addActionListener( this );
		config.add( addLabel( "Color map-", cmaps ) );
		
		data = new JComboBox( volumes.toArray() );
		data.addActionListener( this );
		config.add( addLabel( "Data set-", data ) );
		
		emit = new JComboBox( emits.toArray() );
		emit.addActionListener( this );
		emit.setEnabled( false );
		config.add( addLabel( "Emission-", emit ) );
		
		scale = new JComboBox( scales );
		scale.setSelectedItem(scales[3]);
		scale.addActionListener( this );
		config.add( addLabel( "Scale-", scale ) );
		
		delay = new JComboBox( delays );
		delay.setSelectedItem( delays[3]);
		delay.addActionListener( this );
		config.add( addLabel( "Delay-", delay ) );
		
		openChooser = new JButton( "Background" );
		openChooser.addActionListener( this );
		JPanel tmp = new JPanel( new GridLayout( 1,0) );
		tmp.add( openChooser );
		config.add( tmp );
		
		// add configuration options
		add( BorderLayout.SOUTH, config );
		addKeyListener( this );
		
		// setup the volume.
		last = (Volume)data.getSelectedItem();
		last.setColormap((Colormap)cmaps.getSelectedItem());
		if( last instanceof EmitterVolume )
		{
			((EmitterVolume)last).setEmitter((Emitter)emit.getSelectedItem());
		}
		last.setup();
		
		// set up the canvas.
		setupCanvas();
	}

	
	
	/**
	 * 
	 */
	public void actionPerformed(ActionEvent evt) 
	{
		// if background button pressed, open chooser.
		if( evt.getSource() == openChooser )
		{
			Color c = JColorChooser.showDialog(this,
                      "Choose Background Color",
                      getBackground());
			if( c != null )
				background = new Color3f( c );
		}
		
		// check the remaining fields for updates. 
		Volume volume = (Volume)data.getSelectedItem();
		if( last != null && last != volume )
		{
			last.teardown();
			last = volume;
			last.setup();
		}
		if( last instanceof EmitterVolume )
		{
			((EmitterVolume)last).setEmitter((Emitter)emit.getSelectedItem());
		}
		last.setColormap((Colormap)cmaps.getSelectedItem()); 
		
		// disable emitter for block and random which dont use it.
		if( evt.getSource() == data )
		{
			if( last instanceof EmitterVolume )
			{
				emit.setEnabled( true );
			}
			else
			{
				emit.setEnabled( false );
			}
		}
		
		// setup the canvas again
		setupCanvas();
	}
	
	public void keyPressed(KeyEvent arg0) {}

	public void keyReleased(KeyEvent arg0) {}

	/**
	 * Allows the user to select from some standard configurations.
	 */
	public void keyTyped(KeyEvent evt) {
		switch( evt.getKeyChar() )
		{
			case '1':
				cmaps.setSelectedIndex( 0 );
				data.setSelectedIndex( 1 );
				break;
			case '2':
				cmaps.setSelectedIndex( 0 );
				data.setSelectedIndex( 2 );
				emit.setSelectedIndex( 0 );
				break;
			case '3':
				cmaps.setSelectedIndex( 1 );
				data.setSelectedIndex( 2 );
				emit.setSelectedIndex( 0 );
				break;
			case '4':
				cmaps.setSelectedIndex( 2 );
				data.setSelectedIndex( 2 );
				emit.setSelectedIndex( 0 );
				break;
			case '5':
				cmaps.setSelectedIndex( 1 );
				data.setSelectedIndex( 2 );
				emit.setSelectedIndex( 2 );
				break;
			case '6':
				cmaps.setSelectedIndex( 1 );
				data.setSelectedIndex( 3 );
				emit.setSelectedIndex( 2 );
				break;
			case '7':
				cmaps.setSelectedIndex( 3 );
				data.setSelectedIndex( 4 );
				emit.setSelectedIndex( 3 );
				break;
			case '8':
				cmaps.setSelectedIndex( 3 );
				data.setSelectedIndex( 4 );
				emit.setSelectedIndex( 4 );
				break;
			case '9':
				cmaps.setSelectedIndex( 3 );
				data.setSelectedIndex( 5 );
				emit.setSelectedIndex( 1 );
				break;
			case 'p':
				AnimationBehavior.PAUSE = !AnimationBehavior.PAUSE;
			default:
				return;
		}
		
		setupCanvas();
	}
	
	/**
	 * Dispose of the previous canvas if any, 
	 * 	then create new volume canvas and add it to window.
	 */
	private void setupCanvas()
	{	
		// if not first canvas, dispose of previous canvas
		if( volRend != null ) 
		{
			remove( volRend );
			volRend.removeKeyListener( this );
			volRend.dispose();
		}
		
		// Create volume renderer
		volRend = new VolumeCanvas( last, 
				(Integer)delay.getSelectedItem(), 
				(Float)scale.getSelectedItem(), 
				background );
		volRend.setSize(600, 600);
		volRend.addKeyListener( this );
		volRend.requestFocusInWindow();
		
		// add to center of screen.
		add( BorderLayout.CENTER, volRend );
		validate();
	}
	
	/**
	 * Add the label.
	 * @param label
	 * @param jcomp
	 * @return
	 */
	private JPanel addLabel( String label, Component jcomp )
	{
		JPanel panel = new JPanel( new GridLayout( 0, 1 ) );
		panel.add( new JLabel( label ) );
		panel.add( jcomp );
		return panel;
	}
	
	/**
	 * Open a new frame with a volume renderer.
	 * @param args
	 */
	public static void main(String[] args) 
	{	
		long totalMem = Runtime.getRuntime().totalMemory();
		if( totalMem < 500000 ) 
			System.out.println(  "Warning, heap space might not be large enough: " + totalMem + "." );

		maps.add( new LinearColormap() );
		maps.add( new RedColormap() );
		maps.add( new BlueColormap() );
		maps.add( new SexyColormap() );
		
		volumes.add( new BlockData() );
		volumes.add( new RandomData() );
		volumes.add( new SimpleFuelData() );
		volumes.add( new ExpandingFlameData() );
		volumes.add( new SexyData() );
		volumes.add( new WTFData() );

		
		emits.add( new ConstantEmitter() );
		emits.add( new RandomEmitter() );
		emits.add( new RowEmitter() );
		emits.add( new RandomRowEmitter() );
		emits.add( new OutsideEmitter() );
		
		JFrame frame = new JFrame("Java3D Volume Rendering Editor");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setContentPane( new FireRenderer() );
		frame.pack();
		frame.setVisible( true );
	}
	
}
